﻿using KrasDD.Utils;

namespace KrasDD.Extensions;

public static class CacheExtensions
{
    /// <summary>
    /// 从分布式缓存中获取指定键的值，如果键不存在，则使用指定的工厂方法创建值并添加到缓存中。
    /// </summary>
    /// <typeparam name="T">要获取或设置的值的类型。</typeparam>
    /// <param name="cache">分布式缓存实例。</param>
    /// <param name="key">缓存键。</param>
    /// <param name="valueFactory">用于创建值的工厂方法。</param>
    /// <param name="options">缓存项的选项，可选参数。</param>
    /// <returns>缓存中对应键的值，如果值不存在则返回工厂方法创建的值。</returns>
    public static T GetOrSet<T>(this IDistributedCache cache, string key, Func<T> valueFactory, DistributedCacheEntryOptions options = null)
    {
        var json = cache.GetString(key);
        if (string.IsNullOrEmpty(json))
        {
            var value = valueFactory();
            if (value == null)
                return default;
            if (options == null)
            {
                cache.SetString(key, JSON.Serialize(value));
            }
            else
            {
                cache.SetString(key, JSON.Serialize(value), options);
            }

            return value;
        }
        return JSON.Deserialize<T>(json);
    }

    public static async Task<T> GetOrSetAsync<T>(this IDistributedCache cache, string key, Func<Task<T>> valueFactory, DistributedCacheEntryOptions options = null, CancellationToken token = default)
    {
        var json = await cache.GetStringAsync(key);
        if (string.IsNullOrEmpty(json))
        {
            var value = await valueFactory();
            if (value == null)
                return default;
            if (options == null)
            {
                await cache.SetStringAsync(key, JSON.Serialize(value), token);
            }
            else
            {
                await cache.SetStringAsync(key, JSON.Serialize(value), options, token);
            }
            return value;
        }
        return JSON.Deserialize<T>(json);
    }
}